﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Software41.Tracking.BAM;

namespace Software41.Tracking.BAM.Tests
{
    /// <summary>
    /// Summary description for ExceptionInfoTests
    /// </summary>
    [TestClass]
    public class ExceptionInfoTests
    {
        public ExceptionInfoTests()
        {
            //
            // TODO: Add constructor logic here
            //
        }


        #region Begin Methods
        [TestMethod]
        public void Begin_WithProcessInfo_Success()
        {

            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            var pi = new ProcessTraceInfo(Guid.NewGuid().ToString());

            string parentStepId = Guid.NewGuid().ToString();

            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);
            eventStream.Setup(b => b.BeginActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId));

            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_SOURCE, ex.Source));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_MESSAGE, ex.Message));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_STACKTRACE, ex.StackTrace));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_TYPE, ex.GetType().ToString()));

            eventStream.Setup(b => b.AddRelatedActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ActivityType.ProcessTraceInfo.ToString(), pi.ProcessInfoId));


            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);
            var actualExceptionId = exceptInfo.Begin(pi);

            //Verify
            Assert.AreEqual(exceptionId, actualExceptionId);

            eventStream.VerifyAll();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Begin_WithProcessInfo_IsNull_Fail()
        {
            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            ProcessTraceInfo pi = null;

            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);

            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);
            var actualExceptionId = exceptInfo.Begin(pi);
        }

        [TestMethod]
        public void Begin_WithStepInfo_Success()
        {

            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            var stepInfo = new StepInfo(Guid.NewGuid().ToString());

            string parentStepId = Guid.NewGuid().ToString();

            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);
            eventStream.Setup(b => b.BeginActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId));

            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_SOURCE, ex.Source));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_MESSAGE, ex.Message));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_STACKTRACE, ex.StackTrace));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_TYPE, ex.GetType().ToString()));

            eventStream.Setup(b => b.AddRelatedActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ActivityType.StepInfo.ToString(), stepInfo.StepInfoId));


            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);
            var actualExceptionId = exceptInfo.Begin(stepInfo);

            //Verify
            Assert.AreEqual(exceptionId, actualExceptionId);

            eventStream.VerifyAll();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Begin_WithStepInfo_IsNull_Fail()
        {
            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            ActionInfo stepInfo = null;

            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);

            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);
            var actualExceptionId = exceptInfo.Begin(stepInfo);
        }

        [TestMethod]
        public void Begin_WithActionInfo_Success()
        {

            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            var actionInfo = new ActionInfo(Guid.NewGuid().ToString());

            string parentStepId = Guid.NewGuid().ToString();

            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);
            eventStream.Setup(b => b.BeginActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId));

            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_SOURCE, ex.Source));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_MESSAGE, ex.Message));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_STACKTRACE, ex.StackTrace));
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_TYPE, ex.GetType().ToString()));

            eventStream.Setup(b => b.AddRelatedActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ActivityType.ActionInfo.ToString(), actionInfo.ActionInfoId));


            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);
            var actualExceptionId = exceptInfo.Begin(actionInfo);

            //Verify
            Assert.AreEqual(exceptionId, actualExceptionId);

            eventStream.VerifyAll();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Begin_WithActionInfo_IsNull_Fail()
        {
            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            ActionInfo actionInfo = null;

            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);

            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);
            var actualExceptionId = exceptInfo.Begin(actionInfo);
        }

        #endregion

        #region End Methods

        [TestMethod]
        public void End_WithActionsTakenAppending_Success()
        {

            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            var actionInfo = new ActionInfo(Guid.NewGuid().ToString());

            string parentStepId = Guid.NewGuid().ToString();

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("First String");
            sb.AppendLine("Second String");
            
            
            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_ACTIONSTAKEN, sb.ToString() ));
            eventStream.Setup(b => b.EndActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId));

            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);

            exceptInfo.UpdateActionsTaken("First String");
            exceptInfo.UpdateActionsTaken("Second String");
            exceptInfo.End();

            //Verify
            eventStream.VerifyAll();
        }


        [TestMethod]
        public void End_WithActionsTaken_Success()
        {

            //arrange
            string exceptionId = Guid.NewGuid().ToString();
            var ex = new Exception("Sample Exception");
            var actionInfo = new ActionInfo(Guid.NewGuid().ToString());

            string parentStepId = Guid.NewGuid().ToString();

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Second String");


            Mock<IEventStream> eventStream = new Mock<IEventStream>(MockBehavior.Strict);
            eventStream.Setup(b => b.UpdateActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId,
                                                            ExceptionDetail.EXINFO_ACTIVITY_ACTIONSTAKEN, sb.ToString()));
            eventStream.Setup(b => b.EndActivity(ExceptionDetail.EXINFO_ACTIVITY, exceptionId));

            //act
            var exceptInfo = new ExceptionDetail(ex, exceptionId, eventStream.Object);

            exceptInfo.UpdateActionsTaken("First String");
            exceptInfo.UpdateActionsTaken("Second String", true);
            exceptInfo.End();

            //Verify
            eventStream.VerifyAll();
        }


        #endregion

    }
}
